package com.gylang.user.context.util;

import cn.hutool.core.collection.CollUtil;
import com.gylang.user.context.domain.RightDTO;
import com.gylang.user.context.domain.RoleDTO;
import com.gylang.user.context.domain.UserContextDTO;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.gylang.user.context.constant.ReqContextConstant.*;

/**
 * 用户请求上下文数据
 *
 * @author gylang
 * data 2020/9/2
 * @version v0.0.1
 */
@Slf4j
public class UserContextUtils {

    @Setter
    private static RedisTemplate<String, Object> redisUtils;

    private static HttpServletRequest request() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null == attributes) {
            log.warn("获取不到 ServletRequestAttributes");
            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "获取不到 ServletRequestAttributes");
        }
        return attributes.getRequest();
    }

    public static void pushUserContext(String accessToken, UserContextDTO userContextDTO) {

        //用户基本信息
        Map<String, Object> userContextMap = CollUtil.newHashMap(calculateUserContextSize(userContextDTO));
        userContextMap.put(UID, userContextDTO.getUid());
        userContextMap.put(USERNAME, userContextDTO.getUsername());
        userContextMap.put(NICKNAME, userContextDTO.getNickName());
        userContextMap.put(ROLE_LIST, userContextDTO.getRoleList());
        userContextMap.put(RIGHT_LIST, userContextDTO.getRightList());
        //session 数据
        userContextMap.putAll(userContextDTO.getAttr());
        opsForHash().putAll(ACCESS_TOKEN_KEY + accessToken, userContextMap);
    }

    private static HashOperations<String, String, Object> opsForHash() {
        return redisUtils.opsForHash();
    }

    private static int calculateUserContextSize(UserContextDTO userContextDTO) {
        return 5 + userContextDTO.getAttr().size();
    }

    public static String getUid() {
        return (String) getCacheData(UID);
    }


    public static String getUsername() {
        return (String) getCacheData(USERNAME);
    }


    public static String getNickName() {
        return (String) getCacheData(NICKNAME);

    }

    @SuppressWarnings("unchecked")
    public static List<RoleDTO> getRoleList() {
        return (List<RoleDTO>) getCacheData(ROLE_LIST);
    }

    @SuppressWarnings("unchecked")
    public static List<RightDTO> getRightList() {
        return (List<RightDTO>) getCacheData(RIGHT_LIST);

    }

    public static void setAttr(String attrKey, String value) {
        opsForHash().delete(userContextCacheKey(), attrKey, value);
    }

    public static void removeAttr(Object... attrKey) {
        opsForHash().delete(userContextCacheKey(), attrKey);
    }

    @SuppressWarnings("unchecked")
    public static <T> T getAttr(String attrKey) {
        return (T) opsForHash().get(userContextCacheKey(), attrKey);
    }

    public static List<Object> getAttrValue() {
        return opsForHash().entries(userContextCacheKey()).entrySet().stream()
                .filter(entry -> isAttr(entry.getKey()))
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());

    }

    public static UserContextDTO getUserContext(String accessToken) {
        Map<String, Object> userContextMap = opsForHash().entries(USER_CONTEXT_KEY + accessToken);
        if (null == userContextMap) {
            return null;
        }
        UserContextDTO userContextDTO = new UserContextDTO();
        userContextDTO.setUid((String) userContextMap.get(UID));
        userContextDTO.setUsername((String) userContextMap.get(USERNAME));
        userContextDTO.setNickName((String) userContextMap.get(NICKNAME));
        userContextDTO.setRoleList((List<RoleDTO>) userContextMap.get(ROLE_LIST));
        userContextDTO.setRightList((List<RightDTO>) userContextMap.get(RIGHT_LIST));
        return userContextDTO;
    }
    public static List<String> getAttrKey() {

        return opsForHash().keys(userContextCacheKey()).stream()
                .filter(UserContextUtils::isAttr)
                .map(key -> key.replace(ATTR_PREFIX, EMPTY))
                .collect(Collectors.toList());
    }

    public static Map<String, Object> getAttr() {
        return opsForHash().entries(userContextCacheKey()).entrySet().stream()
                .filter(entry -> isAttr(entry.getKey()))
                .collect(Collectors.toMap(e -> e.getKey().replace(ATTR_PREFIX, EMPTY), Map.Entry::getValue));
    }

    private static Object getCacheData(String nickname) {
        Object data = opsForHash().get(userContextCacheKey(), nickname);
        checkLogin(data);
        return data;
    }

    private static String getAccessToken() {

        HttpServletRequest request = request();
        String accessToken = request.getHeader(ACCESS_TOKEN_KEY);
        //获取token
        accessToken = StringUtils.isEmpty(accessToken) ? (String) request.getAttribute(ACCESS_TOKEN_KEY) : accessToken;
        checkLogin(accessToken);
        return accessToken;

    }

    private static void checkLogin(Object data) {
        if (null == data) {
            throw new IMAuthException("为授权登录");
        }
    }

    private static String userContextCacheKey() {
        return USER_CONTEXT_KEY + getAccessToken();
    }

    private static boolean isAttr(String key) {
        return key.contains(ATTR_PREFIX);
    }
}
